package com.owl.jdbc.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.owl.jdbc.context.DBContextHolder;
import com.owl.jdbc.model.OwlDataSourceModel;
import com.owl.jdbc.properties.SlaveProperties;
import com.owl.jdbc.routing.RoutingDataSource;
import com.owl.jdbc.properties.OwlProperties;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.AbstractApplicationContext;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;


@Configuration
public class DatasourceConfig {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private OwlProperties owlProperties;

    private List<OwlDataSourceModel> slaves;


    private ApplicationContext applicationContext;


    @Bean
    public DataSource masterDataSource(){
        if(owlProperties.getDatasource().getMaster()!=null) {
            if ("com.alibaba.druid.pool.DruidDataSource".equals(owlProperties.getDatasource().getMaster().getType())) {
                DruidDataSource masterDatasource = new DruidDataSource();
                try {
                    masterDatasource.setUrl(owlProperties.getDatasource().getMaster().getUrl());
                    masterDatasource.setUsername(owlProperties.getDatasource().getMaster().getUsername());
                    masterDatasource.setPassword(owlProperties.getDatasource().getMaster().getPassword());
                    masterDatasource.setDriverClassName(owlProperties.getDatasource().getMaster().getDriverClassName());

                    if(owlProperties.getDatasource().getMaster().getInitialSize()!=null) {
                        masterDatasource.setInitialSize(owlProperties.getDatasource().getMaster().getInitialSize());
                    }
                    if(owlProperties.getDatasource().getMaster().getMaxActive()!=null) {
                        masterDatasource.setMaxActive(owlProperties.getDatasource().getMaster().getMaxActive());
                    }
                    if(owlProperties.getDatasource().getMaster().getMinIdle()!=null) {
                        masterDatasource.setMinIdle(owlProperties.getDatasource().getMaster().getMinIdle());
                    }
                    if(owlProperties.getDatasource().getMaster().getValidationQuery()!=null) {
                        masterDatasource.setValidationQuery(owlProperties.getDatasource().getMaster().getValidationQuery());
                    }
                    if(owlProperties.getDatasource().getMaster().getTestOnBorrow()!=null) {
                        masterDatasource.setTestOnBorrow(owlProperties.getDatasource().getMaster().getTestOnBorrow());
                    }
                    masterDatasource.init();
                } catch (SQLException e) {
                    logger.warn(e.getMessage(), e);
                }
                return masterDatasource;
            }
            if (StringUtils.isEmpty(owlProperties.getDatasource().getMaster().getType())) {
                throw new IllegalArgumentException("没有指定数据源连接池");
            }
        }
        return null;
    }


    public List<OwlDataSourceModel> createSlaveDataSources()
    {
        List<OwlDataSourceModel> owlDataSourceModels = new ArrayList<OwlDataSourceModel>();
        if (owlProperties.getDatasource().getSlaves() != null && owlProperties.getDatasource().getSlaves().length > 0) {
            int index=0;
            for (SlaveProperties slaveProperties : owlProperties.getDatasource().getSlaves()) {
                OwlDataSourceModel owlDataSourceModel = new OwlDataSourceModel();
                DruidDataSource datasource = new DruidDataSource();
                try {
                    datasource.setUrl(slaveProperties.getUrl());
                    datasource.setUsername(slaveProperties.getUsername());
                    datasource.setPassword(slaveProperties.getPassword());
                    datasource.setDriverClassName(slaveProperties.getDriverClassName());

                    if (slaveProperties.getInitialSize() != null) {
                        datasource.setInitialSize(slaveProperties.getInitialSize());
                    }
                    if (slaveProperties.getMaxActive() != null) {
                        datasource.setMaxActive(slaveProperties.getMaxActive());
                    }
                    if (slaveProperties.getMinIdle() != null) {
                        datasource.setMinIdle(slaveProperties.getMinIdle());
                    }
                    if (slaveProperties.getValidationQuery() != null) {
                        datasource.setValidationQuery(slaveProperties.getValidationQuery());
                    }
                    if (slaveProperties.getTestOnBorrow() != null) {
                        datasource.setTestOnBorrow(slaveProperties.getTestOnBorrow());
                    }
                    datasource.init();
                    String slaveName = "slave_"+index;
                    slaveProperties.setName(slaveName);
                    owlDataSourceModel.setName(slaveName);
                    owlDataSourceModel.setDataSource(datasource);

                    logger.info("初始化slave {}",datasource.toString());
                    owlDataSourceModels.add(owlDataSourceModel);
                    index++;
                } catch (Exception e) {
                    logger.warn(e.getMessage(), e);
                }
            }
        }
        return owlDataSourceModels;
    }



    public DatasourceConfig(ApplicationContext applicationContext)
    {
        this.applicationContext = applicationContext;
    }


    @Bean
    public DataSource owlRoutingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource) {

        if(masterDataSource==null)
        {
            throw new IllegalArgumentException("数据源主库初始化失败");
        }

        Map<Object, Object> datasources = new HashMap<>();


        DBContextHolder.owlProperties=owlProperties;
        //初始化从库相关配置
        slaves = createSlaveDataSources();

        if (CollectionUtils.isNotEmpty(slaves)) {
            DBContextHolder.slaveCounter = new AtomicInteger(slaves.size());
            for (OwlDataSourceModel owlDataSourceModel : slaves) {
//                ((AbstractApplicationContext) applicationContext).getBeanFactory().registerSingleton(owlDataSourceModel.getName(), owlDataSourceModel.getDataSource());
                datasources.put(owlDataSourceModel.getName(),owlDataSourceModel.getDataSource());
            }
        }


        //初始化主库
        if(masterDataSource!=null) {
            datasources.put("master", masterDataSource);
        }


        logger.info(" init datasourceProperties {} ",datasources.toString());
        RoutingDataSource routingDataSource = new RoutingDataSource();
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        routingDataSource.setTargetDataSources(datasources);
        return routingDataSource;
    }


}
